//#![windows_subsystem = "windows"]
#![windows_subsystem = "console"] 

#[cfg(debug_assertions)]
static APIURL: &'static str = "http://127.0.0.1:8000/api/asset/add";

#[cfg(not(debug_assertions))]
static APIURL: &'static str = "http://127.0.0.1:8000/api/asset/add";

extern crate winreg;
extern crate serde_json;
extern crate static_vcruntime; //https://users.rust-lang.org/t/static-vcruntime-distribute-windows-msvc-binaries-without-needing-to-deploy-vcruntime-dll/57599

use winreg::enums::{HKEY_LOCAL_MACHINE, KEY_READ};
use std::{io::prelude::Write, borrow::Borrow};
use serde::{Serialize};
use std::collections::HashMap;
use chrono::prelude::*;
use serde::Deserialize;
use wmi::{COMLibrary, Variant, WMIConnection, WMIDateTime};


use std::{
    cell::RefCell, 
    iter, mem,
    net::SocketAddr, 
    time::Duration as StdDuration, thread, sync::mpsc::channel, ptr::null
};
use crate::{
    record::{NetRecord, Record, StatRecord, progMsg}, 
};
use packet::{Packet, ip::{v4, Protocol}, udp, tcp};
use byteorder::{self, NetworkEndian, WriteBytesExt};

use crate::{
    filter::{FilterError, create_filter},
    meta, 
    utils::{AppProtocol, attach_console}
};
use std::sync::mpsc::*;

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]    
struct Software {
    name: String,
    auser: String,
    depart: String,
    unit: String,
    acate: String,
    ver: String,
    verid: String,
    productid: String,
    insttime: String,
    partialproductkey: String,
    licensestatus: String,
    value: u32,
    now_value: u32,
    category: String,
    description: String,
    parent_id: String,
    parent: String,
    children_: String,
    status: String,
    owner: String,
    department: String,
    start_time: String,
    service_life: u32,
    custom: String
}
#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct Data {
    data : [Software; 1]
}

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct DataXhange {
    FileVersion: u8,
    BitnessOS: String,
    Jikwaa: Jikwaa,
    Machine: Machine,
    Windows: Windows,
    SystemInformation: SystemInformation,
    HardwareConfig: HardwareConfig,
    Software: HashMap<String,HashMap<String,String>>,
    SoftwareWOW6432Node: HashMap<String,HashMap<String,String>>
    }

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct Machine {
    MachineGuid: String, 
    ComputerName: String, 
    Domain: String, 
    }

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct Jikwaa {
    OrgID: String, 
    SecKey: String,
    }

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct Windows {
    ReleaseId: String, 
    ProductName: String, 
    InstallDate: String, 
    InstallTime: String, 
    EditionID: String,
    EditionSubManufacturer: String,
    EditionSubstring: String,
    EditionSubVersion: String,
    InstallationType: String,
    CurrentVersion: String,
    CurrentType: String,
    CurrentMajorVersionNumber: String,
    CurrentMinorVersionNumber: String,
    }

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct SystemInformation {
    SystemManufacturer: String, 
    SystemProductName: String, 
    BIOSVersion: String, 
    BIOSReleaseDate: String, 
    ComputerHardwareId: String,
    }

#[derive(Serialize, Debug)]
#[allow(non_snake_case)]
struct HardwareConfig {
    BaseBoardManufacturer: String, 
    BaseBoardProduct: String, 
    BIOSReleaseDate: String, 
    BIOSVendor: String, 
    BIOSVersion: String, 
    EnclosureType: String, 
    SystemBiosVersion: String, 
    SystemFamily: String, 
    SystemManufacturer: String, 
    SystemProductName: String, 
    SystemSKU: String, 
    }

fn os_bitness () -> String {
    match bitness::os_bitness() {
        Ok(bitness) => {
            match bitness {
                bitness::Bitness::X86_32 => return "x32".to_string() ,
                bitness::Bitness::X86_64 => return "x64".to_string() ,
                bitness::Bitness::Unknown => return "Unknown".to_string()
                }
            },
        Err(_) => return "Error".to_string(),
        }
    }

fn bytes_to_hex (input: &winreg::RegValue) -> String {
    let mut output: String = "".to_string();
    for x in &input.bytes {
        output = format!("{} {}", output, format!("{:02x}", x));
        }
    return output.trim().to_string();
    }

fn display_reg_value(rv: &winreg::RegValue) -> String {
    use winreg::enums::RegType::*;
    use winreg::types::FromRegValue;
    match rv.vtype {
        REG_NONE                            => "REG_NONE".to_string(),
        REG_SZ                              => String::from_reg_value(rv).unwrap_or_default(),
        REG_EXPAND_SZ                       => String::from_reg_value(rv).unwrap_or_default(),
        REG_MULTI_SZ                        => String::from_reg_value(rv).unwrap_or_default().replace(&['\r', '\n', '\t'][..], " "),
        REG_DWORD                           => u32::from_reg_value(rv).unwrap_or_default().to_string(),
        REG_QWORD                           => u64::from_reg_value(rv).unwrap_or_default().to_string(),
        REG_BINARY                          => bytes_to_hex (rv),
        REG_DWORD_BIG_ENDIAN                => "REG_DWORD_BIG_ENDIAN".to_string(),
        REG_LINK                            => "REG_LINK".to_string(),
        REG_RESOURCE_LIST                   => "REG_RESOURCE_LIST".to_string(),
        REG_FULL_RESOURCE_DESCRIPTOR        => "REG_FULL_RESOURCE_DESCRIPTOR".to_string(),
        REG_RESOURCE_REQUIREMENTS_LIST      => "REG_RESOURCE_REQUIREMENTS_LIST".to_string(),
        }
    }

fn regreadvalue(regpath: &str, regvalue: &str) ->String {
    let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
    let subkey = hklm.open_subkey_with_flags(regpath, KEY_READ);
    match subkey {
        Ok(subkey) => {
            let subvalue = subkey.get_raw_value(regvalue);
            let _strange = match subvalue {
                Ok(subvalue) => return display_reg_value(&subvalue),
                Err(_) => return "".to_string(),
                };
            },
        Err(_) => return "".to_string(),
        }
    }

    pub fn regkeyloop(regpath: &str) -> HashMap<String,HashMap<String,String>> {
        let mut output = HashMap::new();
        let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
        let subkey = hklm.open_subkey_with_flags(regpath, KEY_READ);
        match subkey {
            Ok(subkey) => {
                for name in subkey.enum_keys().map(|x| x.unwrap()) {
                    //println!("-----{}\\{}", regpath,name);
                    output.insert(name.to_string(), regvalloop(format!("{}\\{}",regpath,name).as_str()));
                    }
                return output;
                },
            Err(_) => return output,
            }
        }

    fn regvalloop(regpath: &str) -> HashMap<String,String> {
        let mut output = HashMap::new();
        let hklm = winreg::RegKey::predef(HKEY_LOCAL_MACHINE);
        let subkey = hklm.open_subkey_with_flags(regpath, KEY_READ);
        match subkey {
            Ok(subkey) => {
                for (name, _value) in subkey.enum_values().map(|x| x.unwrap()) {
                    output.insert(name.to_string(), regreadvalue(regpath, name.as_str()));
                    }
                return output;
                },
            Err(_) => return output,
            }
        }

pub fn get_opagent() -> std::io::Result<()>
    {
    let myjson = DataXhange {
        FileVersion : 1 ,
        BitnessOS : os_bitness () ,
        Jikwaa : Jikwaa {
            OrgID: regreadvalue(r#"SOFTWARE\jikwaa"#, "OrgID") ,
            SecKey: regreadvalue(r#"SOFTWARE\jikwaa"#, "SecKey") ,
            } ,
        Machine : Machine {
            MachineGuid: regreadvalue(r#"SOFTWARE\Microsoft\Cryptography"#, "MachineGuid"), 
            ComputerName: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName"#, "ComputerName"), 
            Domain: regreadvalue(r#"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"#, "Domain"), 
            } ,
        Software : regkeyloop (r#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"#),
        SoftwareWOW6432Node : regkeyloop (r#"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"#),
        Windows : Windows {
            ReleaseId: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ReleaseID"), 
            ProductName: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductName"), 
            InstallDate: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallDate"), 
            InstallTime: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallTime"), 
            EditionID: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionID"), 
            EditionSubManufacturer: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubManufacturer"), 
            EditionSubstring: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubstring"), 
            EditionSubVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubVersion"), 
            InstallationType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallationType"), 
            CurrentVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentVersion"), 
            CurrentType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentType"), 
            CurrentMajorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMajorVersionNumber"), 
            CurrentMinorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMinorVersionNumber"), 
            } ,
        SystemInformation : SystemInformation {
            SystemManufacturer: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\SystemInformation"#, "SystemManufacturer"), 
            SystemProductName: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\SystemInformation"#, "SystemProductName"), 
            ComputerHardwareId: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\SystemInformation"#, "ComputerHardwareId"), 
            BIOSVersion: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\SystemInformation"#, "BIOSVersion"), 
            BIOSReleaseDate: regreadvalue(r#"SYSTEM\CurrentControlSet\Control\SystemInformation"#, "BIOSReleaseDate"), 
            } ,
        HardwareConfig : HardwareConfig {
            BaseBoardManufacturer: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "BaseBoardManufacturer"),
            BaseBoardProduct: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "BaseBoardProduct"),
            BIOSReleaseDate: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "BIOSReleaseDate"),
            BIOSVendor: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "BIOSVendor"),
            BIOSVersion: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "BIOSVersion"),
            EnclosureType: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "EnclosureType"),
            SystemBiosVersion: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "SystemBiosVersion"),
            SystemFamily: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "SystemFamily"),
            SystemManufacturer: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "SystemManufacturer"),
            SystemProductName: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "SystemProductName"),
            SystemSKU: regreadvalue(r#"SYSTEM\HardwareConfig\Current"#, "SystemSKU"),
            }
        };

    #[cfg(not(debug_assertions))]
    let mut jsonfile = std::fs::File::create(std::env::temp_dir().display().to_string() + "output.json")?;

    #[cfg(debug_assertions)]
    let mut jsonfile = std::fs::File::create("output.json")?;
    

    //jsonfile.write_all(serde_json::to_string(&myjson).unwrap().as_bytes())?;
    jsonfile.write_all(serde_json::to_string_pretty(&myjson).unwrap().as_bytes())?;

    let resp = attohttpc::post(APIURL)
        .json(&myjson)?                 // set the request body (json feature required)
        .send()?;                       // send the request

    // Check if the status is a 2XX code.
    if resp.is_success()
        {
        // Consume the response body as text and print it.
        if cfg!(debug_assertions)
            {
            println!("Output : {}", resp.text()?);
            }
        }
    else
        {
        println!("ServerError : {}", resp.text()?);
        }

    Ok(())
    }

    pub fn get_windows(sender: &Sender<progMsg>,  aunit: &String, adepart: &String, ausername: &String, aserver: &String)  -> std::io::Result<()> {

        let w =         Windows {
            ReleaseId: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductId"), 
            ProductName: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductName"), 
            InstallDate: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallDate"), 
            InstallTime: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallTime"), 
            EditionID: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionID"), 
            EditionSubManufacturer: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubManufacturer"), 
            EditionSubstring: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubstring"), 
            EditionSubVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubVersion"), 
            InstallationType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallationType"), 
            CurrentVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentVersion"), 
            CurrentType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentType"), 
            CurrentMajorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMajorVersionNumber"), 
            CurrentMinorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMinorVersionNumber"), 
            } ;
        let micro = w.InstallDate.parse::<i64>().unwrap();
        let dt = Local.timestamp_millis(micro*1000);
        let ts = dt.format("%Y-%m-%d %H:%M:%S");

        let soft = Software { 
             name: w.ProductName,
             auser: ausername.to_string(), 
             depart: adepart.to_string(), 
             unit: aunit.to_string(),
             acate: "操作系统".to_owned(), 
             ver: w.EditionID,
             verid: w.CurrentVersion, 
             productid: w.ReleaseId, 
             insttime: ts.to_string(),
             partialproductkey: "".to_owned(),
             licensestatus: "".to_owned(),
              value: 0, 
              now_value: 0,
              category: "".to_owned(),
              description: "".to_owned(), 
              parent_id: "".to_owned(),
               parent: "".to_owned(), 
               children_: "".to_owned(), 
               status: "".to_owned(), 
               owner: "".to_owned(), 
               department: "".to_owned(), 
               start_time: "".to_owned(), 
               service_life: 0, 
               custom: "".to_owned() };
    
        let softarray= [soft];
        let mut data =  Data{data : softarray}; 

        let mut apiurl = String::new();
        apiurl.push_str("http://");
        if aserver.len() < 2 {
            apiurl.push_str("localhost")
        }else{
            apiurl.push_str(aserver);
        }
        apiurl.push_str(":8000/api/asset/add");


        let ww =         Windows {
            ReleaseId: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductId"), 
            ProductName: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductName"), 
            InstallDate: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallDate"), 
            InstallTime: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallTime"), 
            EditionID: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionID"), 
            EditionSubManufacturer: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubManufacturer"), 
            EditionSubstring: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubstring"), 
            EditionSubVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubVersion"), 
            InstallationType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallationType"), 
            CurrentVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentVersion"), 
            CurrentType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentType"), 
            CurrentMajorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMajorVersionNumber"), 
            CurrentMinorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMinorVersionNumber"), 
            } ;
        let rec = Record {
            seq: 1,
            partialkey:"".to_owned(),
            licensestatus:"".to_owned(),
            time: Local::now(),
            src_ip: None,
            src_port: None,
            dest_ip: None,
            dest_port: None,
            len: 0,
            ip_payload_len: None,
            trans_proto: Protocol::Unknown(0),
            trans_payload_len: None,
            app_proto: AppProtocol::Unknown,
            name: ww.ProductName,
            profession: ww.EditionID,
            class: "操作系统".to_owned(),
            version: ww.CurrentVersion,
            id: ww.ReleaseId  
            };

        let args = progMsg {prog: 10, 
        rec: rec};
        sender.send(args).unwrap();

        
        let resp = attohttpc::post(apiurl)
            .json(&data)?                 // set the request body (json feature required)
            .send()?;                              // send the request
        #[cfg(not(debug_assertions))]
        let mut wf = std::fs::File::create(std::env::temp_dir().display().to_string() + "windows.json")?;
        #[cfg(debug_assertions)]
        let mut wf = std::fs::File::create("windows.json")?;
        
        wf.write_all(serde_json::to_string_pretty(&data).unwrap().as_bytes())?;
        // Check if the status is a 2XX code.
        if resp.is_success()
            {
            // Consume the response body as text and print it.
            if cfg!(debug_assertions)
                {
                println!("Output : {}", resp.text()?);
                }
            }
        else
            {
            println!("ServerError : {}", resp.text()?);
            }
        Ok(())    
    }

pub fn get_uninstall(sender: &Sender<progMsg>,  aunit: &String, adepart: &String, ausername: &String, aserver: &String, prog:u32, seq:u32, software: HashMap<String,String>) -> std::io::Result<()>
{
    let mut name = String::new();
    if software.contains_key("DisplayName") {
        let s = software["DisplayName"].clone();
        if s.find("Update for Microsoft")!= None {
            return Ok(());
        }else if s.find("Update for") != None {
            return Ok(());
        }
        name.push_str(&s);
    }else{
        return Ok(());
    }
    let mut ver = String::new();
    if software.contains_key("DisplayVersion") {
        let s = software["DisplayVersion"].clone();
        ver.push_str(&s);
    }
    let mut pid = String::new();
    if software.contains_key("ProductID") {
        let s = software["ProductID"].clone();
        pid.push_str(&s);
    }
    let mut dt = String::new();
    if software.contains_key("InstallDate") {
        let s = software["InstallDate"].clone();
        dt.push_str(&s);
    }

    let curver = &ver;
    let verid = &ver;
    let aname = &name;
    let bname = &name;
    let apid = &pid;
    let bpid = &pid;
    let soft = Software { 
        name: bname.to_string(),
        auser: ausername.to_string(), 
        depart: adepart.to_string(), 
        unit: aunit.to_string(),
        acate: "应用程序".to_owned(), 
        ver: "".to_owned(),
        verid: verid.to_string(), 
        productid: apid.to_string(), 
        insttime: dt,
        partialproductkey: "".to_owned(),
        licensestatus: "".to_owned(),
        value: 0, 
        now_value: 0,
        category: "".to_owned(),
        description: "".to_owned(), 
        parent_id: "".to_owned(),
        parent: "".to_owned(), 
        children_: "".to_owned(), 
        status: "".to_owned(), 
        owner: "".to_owned(), 
        department: "".to_owned(), 
        start_time: "".to_owned(), 
        service_life: 0, 
        custom: "".to_owned() };

    let softarray= [soft];
    let mut myjson =  Data{data : softarray}; 
    #[cfg(not(debug_assertions))]
    let mut jsonfile = std::fs::File::create(std::env::temp_dir().display().to_string() + "uninstall.json")?;

    #[cfg(debug_assertions)]
    let mut jsonfile = std::fs::File::create("uninstall.json")?;


    //jsonfile.write_all(serde_json::to_string(&myjson).unwrap().as_bytes())?;
    jsonfile.write_all(serde_json::to_string_pretty(&myjson).unwrap().as_bytes())?;

    let mut apiurl = String::new();
    apiurl.push_str("http://");
    if aserver.len() < 2 {
        apiurl.push_str("localhost")
    }else{
        apiurl.push_str(aserver);
    }
    apiurl.push_str(":8000/api/asset/add");

    let rec = Record {
        seq: seq,
        partialkey:"".to_owned(),
        licensestatus:"".to_owned(),
        time: Local::now(),
        src_ip: None,
        src_port: None,
        dest_ip: None,
        dest_port: None,
        len: 0,
        ip_payload_len: None,
        trans_proto: Protocol::Unknown(0),
        trans_payload_len: None,
        app_proto: AppProtocol::Unknown,
        name: aname.to_string(),
        profession: "".to_owned(),
        class: "应用软件".to_owned(),
        version: verid.to_string(),
        id: bpid.to_string()  
        };

    let args = progMsg {prog: prog.try_into().unwrap(), 
    rec: rec};
    sender.send(args).unwrap();
    thread::spawn(move ||{
        let resp = attohttpc::post(apiurl)
            .json(&myjson).unwrap()                 // set the request body (json feature required)
            .send().unwrap();                       // send the request

        // Check if the status is a 2XX code.
        if resp.is_success()
            {
            // Consume the response body as text and print it.
            if cfg!(debug_assertions)
                {
                //println!("Output : {}", resp.text()?);
                }
            }
        else
            {
            //println!("ServerError : {}", resp.text()?);
            }
    });
    Ok(())
}



pub fn get_win_activate_stat(sender: &Sender<progMsg>,  aunit: &String, adepart: &String, ausername: &String, aserver: &String) -> Result<(), Box<dyn std::error::Error>>  {
    let com_con = COMLibrary::new()?;
    let wmi_con = WMIConnection::new(com_con.into())?;
    
    let mut results: Vec<HashMap<String, Variant>> = wmi_con.raw_query("SELECT Name, Description, PartialProductKey, LicenseStatus FROM SoftwareLicensingProduct where PartialProductKey <> NULL")?;
    let mv = &results;
    let mut queries = &results;    
    for os in queries{
        println!("{:#?}", os);
    }
    #[cfg(not(debug_assertions))]
    let mut jsonfile = std::fs::File::create(std::env::temp_dir().display().to_string() + "wmic.json")?;

    #[cfg(debug_assertions)]
    let mut jsonfile = std::fs::File::create("wmic.json")?;
    

    //jsonfile.write_all(serde_json::to_string(&myjson).unwrap().as_bytes())?;
    jsonfile.write_all(serde_json::to_string_pretty(&mv).unwrap().as_bytes())?;   

    #[derive(Deserialize, Debug)]
    struct SoftwareLicensingProduct {
        Name: String,
        Description: String,
        PartialProductKey: String,
        LicenseStatus: u32,
    }
    
    let results: Vec<SoftwareLicensingProduct> = wmi_con.raw_query("SELECT Name, Description, PartialProductKey, LicenseStatus FROM SoftwareLicensingProduct where PartialProductKey <> NULL")?;
  
    let w =         Windows {
        ReleaseId: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductId"), 
        ProductName: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "ProductName"), 
        InstallDate: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallDate"), 
        InstallTime: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallTime"), 
        EditionID: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionID"), 
        EditionSubManufacturer: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubManufacturer"), 
        EditionSubstring: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubstring"), 
        EditionSubVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "EditionSubVersion"), 
        InstallationType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "InstallationType"), 
        CurrentVersion: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentVersion"), 
        CurrentType: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentType"), 
        CurrentMajorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMajorVersionNumber"), 
        CurrentMinorVersionNumber: regreadvalue(r#"SOFTWARE\Microsoft\Windows NT\CurrentVersion"#, "CurrentMinorVersionNumber"), 
        } ;

    let mut seq = 0;
    for os in results {
        println!("{:#?}", os);
        let aname = &os.Name;

        let ad = &os.Description;
        let mut licsta = "";
        if os.LicenseStatus == 0 {
            licsta = "无许可";
        }else if os.LicenseStatus == 1 {
            licsta = "已经许可";
        }else if os.LicenseStatus == 2 {
            licsta = "初始宽限期";
        }else if os.LicenseStatus == 3 {
            licsta = "额外宽限期";
        }else if os.LicenseStatus == 4 {
            licsta = "非正版";
        }else if os.LicenseStatus == 5 {
            licsta = "即将过期";
        }else if os.LicenseStatus == 6 {
            licsta = "延长宽限期";
        }else {
            licsta = "未知许可";
        }
        let mut cat = "操作系统";
        let mut name = "";
        let mut verid = "";
        let mut productid = "";
        if os.Name.contains("Office") {
            cat = "应用程序";  
            name = aname;          
        }else {
            name = &w.ProductName;
            verid = &w.CurrentVersion;
            productid = &w.ReleaseId;
        }
        
        let bname = &aname;
        let acat = &cat;
        let bcat = &cat;
        let appk = &os.PartialProductKey;
        let soft = Software { 
            name: name.to_string(),
            auser: ausername.to_string(), 
            depart: adepart.to_string(), 
            unit: aunit.to_string(),
            acate: acat.to_string(), 
            ver: ad.to_string(),
            verid: verid.to_owned(), 
            productid: productid.to_owned(), 
            insttime: "".to_owned(),
            partialproductkey: appk.to_owned(),
            licensestatus: licsta.to_string(),
             value: 0, 
             now_value: 0,
             category: "".to_owned(),
             description: "".to_owned(), 
             parent_id: "".to_owned(),
              parent: "".to_owned(), 
              children_: "".to_owned(), 
              status: "".to_owned(), 
              owner: "".to_owned(), 
              department: "".to_owned(), 
              start_time: "".to_owned(), 
              service_life: 0, 
              custom: "".to_owned() };   

        let softarray= [soft];
        let mut data =  Data{data : softarray}; 

        let mut apiurl = String::new();
        apiurl.push_str("http://");
        if aserver.len() < 2 {
            apiurl.push_str("localhost")
        }else{
            apiurl.push_str(aserver);
        }
        apiurl.push_str(":8000/api/asset/add");

        let ppk = &os.PartialProductKey;
        seq += 1;
        let rec = Record {
            seq: seq,
            partialkey:ppk.to_owned(),
            licensestatus: licsta.to_owned(),
            time: Local::now(),
            src_ip: None,
            src_port: None,
            dest_ip: None,
            dest_port: None,
            len: 0,
            ip_payload_len: None,
            trans_proto: Protocol::Unknown(0),
            trans_payload_len: None,
            app_proto: AppProtocol::Unknown,
            name: name.to_string(),
            profession: os.Description,
            class: bcat.to_string(),
            version: verid.to_owned(),
            id: productid.to_owned()  
            };

        let args = progMsg {prog: 5, 
        rec: rec};
        sender.send(args).unwrap();

        let handle = thread::spawn(move ||{
            let resp = attohttpc::post(apiurl)
            .json(&data).unwrap()                 // set the request body (json feature required)
            .send().unwrap();                              // send the request

            // Check if the status is a 2XX code.
            if resp.is_success()
                {
                // Consume the response body as text and print it.
                if cfg!(debug_assertions)
                    {
                    //println!("Output : {}", resp.text()?);
                    }
                }
            else
                {
                //println!("ServerError : {}", resp.text()?);
                }
        });
        //调用join，让主线程等待至子线程执行完毕
        //unwrap的作用：请求返回结果，如果报错就会panic并停止程序
        //handle.join().unwrap();
        handle.join();
    }
    
    Ok(())
}